package org.truenewx.tnxjee.repo.mybatis.mapper.query;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.baomidou.mybatisplus.core.mapper.Mapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.metadata.TableFieldInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import com.baomidou.mybatisplus.core.override.MybatisMapperMethod;
import org.apache.ibatis.binding.MapperMethod;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.SqlSession;
import org.springframework.cglib.proxy.Enhancer;
import org.truenewx.tnxjee.core.util.BeanUtil;
import org.truenewx.tnxjee.core.util.ClassUtil;
import org.truenewx.tnxjee.model.query.QueryResult;
import org.truenewx.tnxjee.model.query.Querying;
import org.truenewx.tnxjee.repo.mybatis.model.query.QueryResultPage;
import org.truenewx.tnxjee.repo.mybatis.model.query.QueryResultPageProxy;

public class QueryMapperMethod extends MybatisMapperMethod {

    private String commandName;
    private Map<String, String> fieldColumnNameMapping;

    public QueryMapperMethod(Class<?> mapperInterface, Method method, Configuration configuration) {
        super(mapperInterface, method, configuration);
        if (!method.isDefault() && QueryResult.class.isAssignableFrom(method.getReturnType())) {
            Class<?>[] parameterTypes = method.getParameterTypes();
            if (parameterTypes.length == 1 && Querying.class.isAssignableFrom(parameterTypes[0])) {
                MapperMethod.SqlCommand command = BeanUtil.getFieldValue(this, "command");
                this.commandName = command.getName();
                Class<Object> entityType = ClassUtil.getActualGenericType(mapperInterface, Mapper.class, 0);
                if (entityType != null) {
                    this.fieldColumnNameMapping = new HashMap<>();
                    TableInfo tableInfo = TableInfoHelper.getTableInfo(entityType);
                    List<TableFieldInfo> fieldList = tableInfo.getFieldList();
                    for (TableFieldInfo fieldInfo : fieldList) {
                        String fieldName = fieldInfo.getField().getName();
                        String columnName = fieldInfo.getColumn();
                        if (!fieldName.equals(columnName)) {
                            this.fieldColumnNameMapping.put(fieldName, columnName);
                        }
                    }
                }
            }
        }
    }

    @Override
    @SuppressWarnings({"rawtypes", "unchecked"})
    public Object execute(SqlSession sqlSession, Object[] args) {
        if (this.commandName != null) {
            Querying querying = (Querying) args[0];
            QueryResultPageProxy pageProxy = new QueryResultPageProxy(querying);
            pageProxy.setFieldColumnNameMapping(this.fieldColumnNameMapping);
            IPage page = (IPage) Enhancer.create(querying.getClass(), new Class[]{IPage.class}, pageProxy);
            List<?> list = sqlSession.selectList(this.commandName, page);
            page.setRecords(list);
            return new QueryResultPage(page);
        }
        return super.execute(sqlSession, args);
    }

}
